package v10

import (
	"fmt"
	"go-demo/orm/interval/errs"
	"go-demo/orm/v10-insert/interval/model"
	"reflect"
	"strings"
)

// Inserter 上面实现 From where 等 select 语句的方法，最终通过实现 build 方法 构建出Query对象
type Inserter[T any] struct {
	db      *DB
	sb      strings.Builder
	model   *model.Model
	columns []string
	values  []*T
	args    []any
}

func (i *Inserter[T]) Values(vals ...*T) *Inserter[T] {
	i.values = vals
	return i
}

func (i *Inserter[T]) Columns(cols ...string) *Inserter[T] {
	i.columns = cols
	return i
}

func (i *Inserter[T]) Build() (*Query, error) {
	if len(i.values) == 0 {
		return nil, errs.ErrInsertZeroRow
	}
	var err error
	// 先获取元数据
	i.model, err = i.db.registry.Get(new(T))
	if err != nil {
		return nil, err
	}

	i.sb.WriteString(fmt.Sprintf("INSERT INTO `%s`(", i.model.TableName))

	fields := i.model.Fields
	// 拼选择的列
	if len(i.columns) != 0 { // 如果有定义列，则使用自定义列的字段
		fields = make([]*model.Field, 0, len(i.columns))
		for _, c := range i.columns {
			field, ok := i.model.FieldMap[c]
			if !ok {
				return nil, errs.NewErrUnknownField(c)
			}
			fields = append(fields, field)
		}
	}
	i.args = make([]any, 0, len(fields)*len(i.values))

	// 拼 values
	for idx, fd := range fields {
		if idx > 0 {
			i.sb.WriteByte(',')
		}
		i.sb.WriteByte('`')
		i.sb.WriteString(fd.ColName)
		i.sb.WriteByte('`')
	}
	i.sb.WriteString(") VALUES")
	for vIdx, val := range i.values {
		if vIdx > 0 {
			i.sb.WriteByte(',')
		}
		refVal := reflect.ValueOf(val).Elem()
		i.sb.WriteByte('(')
		for fIdx, field := range fields {
			if fIdx > 0 {
				i.sb.WriteByte(',')
			}
			i.sb.WriteByte('?')
			fdVal := refVal.Field(field.Index)
			i.addArgs(fdVal.Interface())
		}
		i.sb.WriteByte(')')
	}
	i.sb.WriteString(";")
	return &Query{
		SQL:  i.sb.String(),
		Args: i.args,
	}, nil

}

func (i *Inserter[T]) addArgs(args ...any) {
	i.args = append(i.args, args...)
}

func NewInserter[T any](db *DB) *Inserter[T] {
	return &Inserter[T]{
		db: db,
	}
}
